package bank;

import app.Const;
import app.kit.CommonKit;
import app.models.analyze.Interfacecallrecord;
import bank.resp.AccountAmountRspDto;
import bank.resp.BindUserRspDto;
import bank.resp.BindUserStatusRspDto;
import bank.resp.MerchantAccntRspDto;
import bank.resp.OrderInfoRspDto;
import bank.resp.ReconciliationDto;
import bank.resp.TransferMerchantRspDto;
import bank.resp.UnBindUserRspDto;
import com.google.common.base.Optional;
import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import com.hundsun.epay.pay.CodeUtil;
import com.hundsun.epay.pay.certkey.CertUtil;
import goja.GojaConfig;
import goja.Logger;
import goja.StringPool;
import goja.date.DateFormatter;
import org.apache.commons.io.IOUtils;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import static bank.BankConstant.BP_BIZ_DATE;
import static bank.BankConstant.BP_CHANNEL_NO;
import static bank.BankConstant.BP_CHARSET;
import static bank.BankConstant.BP_CREATE_DATE;
import static bank.BankConstant.BP_CREATE_TIME;
import static bank.BankConstant.BP_FIELD_1;
import static bank.BankConstant.BP_FIELD_2;
import static bank.BankConstant.BP_FIELD_3;
import static bank.BankConstant.BP_MSG_ID;
import static bank.BankConstant.BP_PARTNER_BUYER_ID;
import static bank.BankConstant.BP_PARTNER_ID;
import static bank.BankConstant.BP_PUBLIC_KEY_CODE;
import static bank.BankConstant.BP_SERVICE;
import static bank.BankConstant.BP_SVR_CODE;
import static bank.BankConstant.BP_VERSION;
import static bank.BankConstant.CNY;
import static bank.BankConstant.DATE_FORMATTER;
import static bank.BankConstant.PARTNERID;
import static bank.BankConstant.PUBLIC_KEY_CODE;
import static bank.BankConstant.TIME_FORMAT;
import static bank.BankConstant.VERSION;
import static goja.StringPool.EMPTY;

/**
 * <p> </p>
 *
 * @author sogYF
 * @version 1.0
 * @since JDK 1.6
 */
public class BankService {


    private static final String BANK_URL    = GojaConfig.getProperty("bank.url");
    private static final String M = "m";


    /**
     * 获取单例对象,如果要调用该单例的使用,只能通过该方法获取.
     */
    public static final BankService me = new BankService();

    /**
     * 订单支持参数签名，
     *
     * @param createDatetime 创建时间
     * @param bizDate        业务时间
     * @param partnerBuyerId 会员号
     * @param outerOrderNo   订单号
     * @param subject        标题
     * @param body           内容
     * @param amount         金额，小数点两位
     * @param returnUrl      同步通知地址
     * @param notifyUrl      异步同志地址
     * @return 签名信息及参数
     */
    public Optional<Map<String, String>> nopwdCreateOrderSign(DateTime createDatetime, DateTime bizDate,
                                                              String partnerBuyerId, String outerOrderNo,
                                                              String subject, String body, String amount,
                                                              String returnUrl, String notifyUrl) {
        String createDate = createDatetime.toString(DATE_FORMATTER);
        String createTime = createDatetime.toString(DateTimeFormat.forPattern(TIME_FORMAT));

        String bizDateStr = bizDate.toString(DATE_FORMATTER);

        createDate = CodeUtil.enCode(createDate, StringPool.UTF_8);
        createTime = CodeUtil.enCode(createTime, StringPool.UTF_8);
        bizDateStr = CodeUtil.enCode(bizDateStr, StringPool.UTF_8);
        String msgID = CodeUtil.enCode(EMPTY, StringPool.UTF_8);
        String svrCode = CodeUtil.enCode(EMPTY, StringPool.UTF_8);
        String partnerId = CodeUtil.enCode(PARTNERID, StringPool.UTF_8);
        String channelNo = CodeUtil.enCode(M, StringPool.UTF_8);
        String field1 = CodeUtil.enCode(EMPTY, StringPool.UTF_8);
        String field2 = CodeUtil.enCode(EMPTY, StringPool.UTF_8);
        String field3 = CodeUtil.enCode(EMPTY, StringPool.UTF_8);
        String version = CodeUtil.enCode(VERSION, StringPool.UTF_8);
//           signType      =CodeUtil.enCode(signType, StringPool.UTF_8);
        String service = CodeUtil.enCode("nopwdCreateOrder", StringPool.UTF_8);
        String publicKeyCode = CodeUtil.enCode(PUBLIC_KEY_CODE, StringPool.UTF_8);
        partnerBuyerId = CodeUtil.enCode(partnerBuyerId, StringPool.UTF_8);
        outerOrderNo = CodeUtil.enCode(outerOrderNo, StringPool.UTF_8);
        subject = CodeUtil.enCode(subject, StringPool.UTF_8);
        amount = CodeUtil.enCode(amount, StringPool.UTF_8);
        String currency = CodeUtil.enCode(CNY, StringPool.UTF_8);
        body = CodeUtil.enCode(body, StringPool.UTF_8);
        //  3 秒自动跳转
        String jumpSec = CodeUtil.enCode("3", StringPool.UTF_8);
        returnUrl = CodeUtil.enCode(returnUrl, StringPool.UTF_8);
        notifyUrl = CodeUtil.enCode(notifyUrl, StringPool.UTF_8);

        Map<String, String> paramMap = Maps.newHashMapWithExpectedSize(25);
        paramMap.put(BP_CREATE_DATE, createDate);
        paramMap.put(BP_CREATE_TIME, createTime);
        paramMap.put(BP_BIZ_DATE, bizDateStr);
        paramMap.put(BP_MSG_ID, msgID);
        paramMap.put(BP_SVR_CODE, svrCode);
        paramMap.put(BP_PARTNER_ID, partnerId);
        paramMap.put(BP_CHANNEL_NO, channelNo);
        paramMap.put(BP_FIELD_1, field1);
        paramMap.put(BP_FIELD_2, field2);
        paramMap.put(BP_FIELD_3, field3);
        paramMap.put(BP_VERSION, version);
        paramMap.put(BP_CHARSET, StringPool.UTF_8);
        paramMap.put(BP_SERVICE, service);
        paramMap.put(BP_PUBLIC_KEY_CODE, publicKeyCode);
        paramMap.put(BP_PARTNER_BUYER_ID, partnerBuyerId);
        paramMap.put("outerOrderNo", outerOrderNo);
        paramMap.put("signType", "RSA");
        paramMap.put("subject", subject);
        paramMap.put(Const.FIELD_AMOUNT, amount);
        paramMap.put("currency", currency);
        paramMap.put("body", body);
        paramMap.put("jumpSec", jumpSec);
        paramMap.put("returnUrl", returnUrl);
        paramMap.put("notifyUrl", notifyUrl);

        String joinStr;
        try {
            joinStr = CodeUtil.getJoinStrByParamMap(paramMap);
            String new_sign = CertUtil.getSign4Merchant(joinStr);
            paramMap.put("sign", new_sign);
            return Optional.of(paramMap);
        } catch (Exception e) {
            Logger.error("Bank Sign [ nopwdCreateOrder ] has error!", e);
        }

        return Optional.absent();

    }


    /**
     * 对公向个人账户打款
     *
     * @param createDatetime 发送时间
     * @param bizDate        业务时间
     * @param partnerBuyerId 会员ID
     * @param outerOrderNo   订单号
     * @param amount         金额
     * @param desc           打款描述
     */
    public Optional<TransferMerchantRspDto> transferMerchantAccnt(DateTime createDatetime, DateTime bizDate,
                                                                  String partnerBuyerId,
                                                                  String outerOrderNo,
                                                                  BigDecimal amount, String desc) {
        String unSigncontent;

        Map<String, String> m = Maps.newHashMap();

        m.put(BP_CREATE_DATE, createDatetime.toString(DATE_FORMATTER));
        m.put(BP_CREATE_TIME, createDatetime.toString(DateTimeFormat.forPattern(TIME_FORMAT)));
        m.put(BP_BIZ_DATE, bizDate.toString(DATE_FORMATTER));
        m.put(BP_MSG_ID, StringPool.EMPTY);
        m.put(BP_SVR_CODE, StringPool.EMPTY);
        m.put(BP_PARTNER_ID, PARTNERID);
        m.put(BP_CHANNEL_NO, M);
        m.put(BP_PUBLIC_KEY_CODE, PUBLIC_KEY_CODE);
        m.put(BP_FIELD_1, StringPool.EMPTY);
        m.put(BP_FIELD_2, StringPool.EMPTY);
        m.put(BP_FIELD_3, StringPool.EMPTY);
        m.put(BP_VERSION, VERSION);
        m.put(BP_CHARSET, StringPool.UTF_8);

        m.put(BP_SERVICE, "transferMerchantAccnt");
        m.put(BP_PARTNER_BUYER_ID, partnerBuyerId);
        m.put("outerOrderNo", outerOrderNo);
        m.put(Const.FIELD_AMOUNT, CommonKit.stringDecimal(amount));
        m.put("currency", CNY);
        m.put("desc", desc);

        unSigncontent = sortParams(m);

        Interfacecallrecord interfacecallrecord = Interfacecallrecord.createRecord("transferMerchantAccnt", partnerBuyerId, bizDate,unSigncontent);

        String signcontent;
        try {
            signcontent = CertUtil.keyPairSign4Merchant(unSigncontent);
            String s = sendHttpMsg(signcontent);
            interfacecallrecord.setResponse(s);
            Logger.info("Bank Interface [ transferMerchantAccnt ] back is {}", s);
            return Optional.of(TransferMerchantRspDto.buildRsp(s));
        } catch (Exception e) {
            e.printStackTrace();
            interfacecallrecord.setFail("银行接口错误，无法转账");
            Logger.error("Bank Interface [ transferMerchantAccnt ] has error!", e);
        } finally {
            interfacecallrecord.save();
        }
        return Optional.absent();

    }


    /**
     * 对账纪录
     *
     * @param createDatetime 发送时间
     * @param bizDate        业务时间
     * @param beginDate      开始日期
     * @param endDate        结束日期
     * @param page           页码
     * @param recordNum      每页显示数量
     */
    public Optional<ReconciliationDto> checkAccount(DateTime createDatetime, DateTime bizDate,
                                                    DateTime beginDate, DateTime endDate,
                                                    int page, int recordNum) {
        String unSigncontent;
        Map<String, String> m = Maps.newHashMap();

        m.put(BP_CREATE_DATE, createDatetime.toString(DATE_FORMATTER));
        m.put(BP_CREATE_TIME, createDatetime.toString(DateTimeFormat.forPattern(TIME_FORMAT)));
        m.put(BP_BIZ_DATE, bizDate.toString(DATE_FORMATTER));
        m.put(BP_MSG_ID, StringPool.EMPTY);
        m.put(BP_SVR_CODE, StringPool.EMPTY);
        m.put(BP_PARTNER_ID, PARTNERID);
        m.put(BP_CHANNEL_NO, M);
        m.put(BP_PUBLIC_KEY_CODE, PUBLIC_KEY_CODE);
        m.put(BP_FIELD_1, StringPool.EMPTY);
        m.put(BP_FIELD_2, StringPool.EMPTY);
        m.put(BP_FIELD_3, StringPool.EMPTY);
        m.put(BP_VERSION, VERSION);
        m.put(BP_CHARSET, StringPool.UTF_8);

        m.put("service", "checkAccout");
        m.put("beginDate", beginDate.toString(DateFormatter.YYYYMMDD));
        m.put("endDate", endDate.toString(DateFormatter.YYYYMMDD));
        m.put("pageId", String.valueOf(page));
        m.put("recordNum", String.valueOf(recordNum));

        unSigncontent = sortParams(m);

        String signcontent;
        try {
            signcontent = CertUtil.keyPairSign4Merchant(unSigncontent);
            String s = sendHttpMsg(signcontent);
            return Optional.of(ReconciliationDto.parseResponse(s));
        } catch (Exception e) {
            e.printStackTrace();
            Logger.error("Bank Interface [ checkAccout ] has error!", e);
        }
        return Optional.absent();

    }


    /**
     * 查看账户绑定信息
     *
     * @param createDatetime 发送时间
     * @param bizDate        业务时间
     * @param partnerBuyerId 会员ID
     * @return 绑定状态
     */
    public Optional<BindUserStatusRspDto> getBindUserStatus(DateTime createDatetime, DateTime bizDate,
                                                           String partnerBuyerId) {
        String unSigncontent;
        Map<String, String> m = Maps.newHashMap();

        m.put(BP_CREATE_DATE, createDatetime.toString(DATE_FORMATTER));
        m.put(BP_CREATE_TIME, createDatetime.toString(DateTimeFormat.forPattern(TIME_FORMAT)));
        m.put(BP_BIZ_DATE, bizDate.toString(DATE_FORMATTER));
        m.put(BP_MSG_ID, StringPool.EMPTY);
        m.put(BP_SVR_CODE, StringPool.EMPTY);
        m.put(BP_PARTNER_ID, PARTNERID);
        m.put(BP_CHANNEL_NO, M);
        m.put(BP_PUBLIC_KEY_CODE, PUBLIC_KEY_CODE);
        m.put(BP_FIELD_1, StringPool.EMPTY);
        m.put(BP_FIELD_2, StringPool.EMPTY);
        m.put(BP_FIELD_3, StringPool.EMPTY);
        m.put(BP_VERSION, VERSION);
        m.put(BP_CHARSET, StringPool.UTF_8);

        m.put(BP_SERVICE, "getBindUserStatus");
        m.put(BP_PARTNER_BUYER_ID, partnerBuyerId);

        unSigncontent = sortParams(m);
        String signcontent;
        try {
            signcontent = CertUtil.keyPairSign4Merchant(unSigncontent);

            String returnContent = sendHttpMsg(signcontent);

            Logger.info("the message is \n{}", returnContent);

            return Optional.of(BindUserStatusRspDto.build(returnContent));
        } catch (Exception e) {
            e.printStackTrace();
            Logger.error("Bank Interface [ getBindUserStatus ] has error!", e);
        }

        return Optional.absent();

    }


    /**
     * 解绑用户
     *
     * @param createDatetime 发送时间
     * @param bizDate        业务时间
     * @param partnerBuyerId 会员ID
     * @return 操作信息
     */
    public Optional<UnBindUserRspDto> unBindUser(DateTime createDatetime, DateTime bizDate,
                                                      String partnerBuyerId) {
        String unSigncontent;
        Map<String, String> m = Maps.newHashMap();

        m.put(BP_CREATE_DATE, createDatetime.toString(DATE_FORMATTER));
        m.put(BP_CREATE_TIME, createDatetime.toString(DateTimeFormat.forPattern(TIME_FORMAT)));
        m.put(BP_BIZ_DATE, bizDate.toString(DATE_FORMATTER));
        m.put(BP_MSG_ID, StringPool.EMPTY);
        m.put(BP_SVR_CODE, StringPool.EMPTY);
        m.put(BP_PARTNER_ID, PARTNERID);
        m.put(BP_CHANNEL_NO, M);
        m.put(BP_PUBLIC_KEY_CODE, PUBLIC_KEY_CODE);
        m.put(BP_FIELD_1, StringPool.EMPTY);
        m.put(BP_FIELD_2, StringPool.EMPTY);
        m.put(BP_FIELD_3, StringPool.EMPTY);
        m.put(BP_VERSION, VERSION);
        m.put(BP_CHARSET, StringPool.UTF_8);

        m.put(BP_SERVICE, "unbindUserInfo");
        m.put(BP_PARTNER_BUYER_ID, partnerBuyerId);

        unSigncontent = sortParams(m);

        String signcontent;
        try {
            signcontent = CertUtil.keyPairSign4Merchant(unSigncontent);

            String s = sendHttpMsg(signcontent);
            Logger.info("the response is \n {}", s);
            return Optional.of(UnBindUserRspDto.build(s));
        } catch (Exception e) {
            Logger.error("Bank Interface [ unbindUserInfo ] has error!", e);
        }
        return Optional.absent();

    }


    /**
     * 绑定电子账户
     *
     * @param createDatetime 发送时间
     * @param bizDate        业务时间
     * @param partnerBuyerId 会员ID
     * @param certNo         身份证号
     * @param realName       真实姓名
     * @param mobile         手机号码
     * @param accountNo      电子账户
     * @return 绑定信息
     */
    public Optional<BindUserRspDto> bindUser(DateTime createDatetime, DateTime bizDate,
                                              String partnerBuyerId, String certNo,
                                              String realName, String mobile, String accountNo) {
        String unSigncontent;
        Map<String, String> m = Maps.newHashMap();

        m.put(BP_CREATE_DATE, createDatetime.toString(DATE_FORMATTER));
        m.put(BP_CREATE_TIME, createDatetime.toString(DateTimeFormat.forPattern(TIME_FORMAT)));
        m.put(BP_BIZ_DATE, bizDate.toString(DATE_FORMATTER));
        m.put(BP_MSG_ID, StringPool.EMPTY);
        m.put(BP_SVR_CODE, StringPool.EMPTY);
        m.put(BP_PARTNER_ID, PARTNERID);
        m.put(BP_CHANNEL_NO, M);
        m.put(BP_PUBLIC_KEY_CODE, PUBLIC_KEY_CODE);
        m.put(BP_FIELD_1, StringPool.EMPTY);
        m.put(BP_FIELD_2, StringPool.EMPTY);
        m.put(BP_FIELD_3, StringPool.EMPTY);
        m.put(BP_VERSION, VERSION);
        m.put(BP_CHARSET, StringPool.UTF_8);

        m.put(BP_SERVICE, "bindUserInfo");

        // 0身份证 1 护照
        m.put("certType", "0");

        m.put(BP_PARTNER_BUYER_ID, partnerBuyerId);
        m.put("certNo", certNo);
        m.put("realName", realName);
        m.put("mobile", mobile);
        m.put("accountNo", accountNo);

        unSigncontent = sortParams(m);

        Interfacecallrecord interfacecallrecord = Interfacecallrecord.createRecord("bindUserInfo", partnerBuyerId, bizDate,unSigncontent);
        String signcontent;
        try {
            signcontent = CertUtil.keyPairSign4Merchant(unSigncontent);
            String s = sendHttpMsg(signcontent);
            interfacecallrecord.setResponse(s);
            Logger.info("the response is \n {}", s);
            if(!Strings.isNullOrEmpty(s)){
                return Optional.of(BindUserRspDto.build(s));
            } else {
                Logger.error("Bank Interface [ bindUserInfo ] return empty message! ");
                return Optional.absent();
            }
        } catch (Exception e) {
            interfacecallrecord.setFail("银行接口访问错误");
            Logger.error("Bank Interface [ bindUserInfo ] has error!", e);
        } finally {
            interfacecallrecord.save();
        }
        return Optional.absent();

    }

    /**
     * 对公账户充值到对公电子账户（开鑫贷B2B转账）
     *
     * @param bizDate 日期
     * @param orderNo 订单号
     * @param amount  金额
     * @return 是否操作成功
     */
    public Optional<MerchantAccntRspDto> rechargeMerchantAccnt(DateTime bizDate, String orderNo, BigDecimal amount) {
        String unSigncontent;
        Map<String, String> m = Maps.newHashMap();

        DateTime createDatetime = DateTime.now();
        m.put(BP_CREATE_DATE, createDatetime.toString(DATE_FORMATTER));
        m.put(BP_CREATE_TIME, createDatetime.toString(DateTimeFormat.forPattern(TIME_FORMAT)));
        m.put(BP_BIZ_DATE, bizDate.toString(DATE_FORMATTER));
        m.put(BP_MSG_ID, StringPool.EMPTY);
        m.put(BP_SVR_CODE, StringPool.EMPTY);
        m.put(BP_PARTNER_ID, PARTNERID);
        m.put(BP_CHANNEL_NO, M);
        m.put(BP_PUBLIC_KEY_CODE, PUBLIC_KEY_CODE);
        m.put(BP_FIELD_1, StringPool.EMPTY);
        m.put(BP_FIELD_2, StringPool.EMPTY);
        m.put(BP_FIELD_3, StringPool.EMPTY);
        m.put(BP_VERSION, VERSION);
        m.put(BP_CHARSET, StringPool.UTF_8);

        m.put("service", "rechargeMerchantAccnt");
        m.put("amount", CommonKit.stringDecimal(amount));
        m.put("currency", "CNY");
        m.put("outerOrderNo", orderNo);
        m.put("desc", "账户充值");
        unSigncontent = sortParams(m);

        Interfacecallrecord interfacecallrecord = Interfacecallrecord.createRecord("rechargeMerchantAccnt", PARTNERID, bizDate,unSigncontent);
        String signcontent;
        try {
            signcontent = CertUtil.keyPairSign4Merchant(unSigncontent);
            String s = sendHttpMsg(signcontent);
            if (!Strings.isNullOrEmpty(s)) {
                interfacecallrecord.setResponse(s);
                Logger.info("the bank Interface [rechargeMerchantAccnt] response is {}", s);
                return Optional.of(MerchantAccntRspDto.create(s));
            } else {
                interfacecallrecord.setFail("银行返回内容为空");
                Logger.error("Bank Interface [ rechargeMerchantAccnt ] return empty message! ");
                return Optional.absent();
            }
        } catch (Exception e) {
            interfacecallrecord.setFail("银行接口访问错误");
            Logger.error("Bank Interface [ rechargeMerchantAccnt ] has error!", e);
        } finally {
            interfacecallrecord.save();
        }
        return Optional.absent();
    }


    /**
     * 对 公电子账户提现到对公账户（开鑫贷B2B转账）
     *
     * @param bizDate 日期
     * @param orderNo 订单号
     * @param amount  金额
     * @return 操作成功
     */
    public Optional<MerchantAccntRspDto> withdrawMerchantAccnt(DateTime bizDate, String orderNo, BigDecimal amount) {
        String unSigncontent;
        Map<String, String> m = Maps.newHashMap();

        DateTime createDatetime = DateTime.now();
        m.put(BP_CREATE_DATE, createDatetime.toString(DATE_FORMATTER));
        m.put(BP_CREATE_TIME, createDatetime.toString(DateTimeFormat.forPattern(TIME_FORMAT)));
        m.put(BP_BIZ_DATE, bizDate.toString(DATE_FORMATTER));
        m.put(BP_MSG_ID, StringPool.EMPTY);
        m.put(BP_SVR_CODE, StringPool.EMPTY);
        m.put(BP_PARTNER_ID, PARTNERID);
        m.put(BP_CHANNEL_NO, M);
        m.put(BP_PUBLIC_KEY_CODE, PUBLIC_KEY_CODE);
        m.put(BP_FIELD_1, StringPool.EMPTY);
        m.put(BP_FIELD_2, StringPool.EMPTY);
        m.put(BP_FIELD_3, StringPool.EMPTY);
        m.put(BP_VERSION, VERSION);
        m.put(BP_CHARSET, StringPool.UTF_8);

        m.put("service", "withdrawMerchantAccnt");
        m.put("amount", CommonKit.stringDecimal(amount));
        m.put("currency", "CNY");
        m.put("outerOrderNo", orderNo);
        m.put("desc", "账户提现");
        unSigncontent = sortParams(m);
        Interfacecallrecord interfacecallrecord = Interfacecallrecord.createRecord("withdrawMerchantAccnt", PARTNERID, bizDate,unSigncontent);

        String signcontent;
        try {
            signcontent = CertUtil.keyPairSign4Merchant(unSigncontent);
            String s = sendHttpMsg(signcontent);
            if (!Strings.isNullOrEmpty(s)) {
                interfacecallrecord.setResponse(s);
                Logger.info("the bank Interface [withdrawMerchantAccnt] response is {}", s);
                return Optional.of(MerchantAccntRspDto.create(s));
            } else {
                interfacecallrecord.setFail("银行返回内容为空");
                Logger.error("Bank Interface [ withdrawMerchantAccnt ] return empty message! ");
                return Optional.absent();
            }
        } catch (Exception e) {
            interfacecallrecord.setFail("银行接口访问错误");
            Logger.error("Bank Interface [ withdrawMerchantAccnt ] has error!", e);
        } finally {
            interfacecallrecord.save();
        }
        return Optional.absent();
    }

    /**
     * 查询订单信息
     *
     * @param createDatetime 发送时间
     * @param bizDate        业务时间
     * @param orderNo        订单号
     * @return 订单信息
     */
    public Optional<OrderInfoRspDto> getOrderInfo(DateTime createDatetime, DateTime bizDate, String orderNo) {
        String unSigncontent;
        Map<String, String> m = Maps.newHashMap();

        m.put(BP_CREATE_DATE, createDatetime.toString(DATE_FORMATTER));
        m.put(BP_CREATE_TIME, createDatetime.toString(DateTimeFormat.forPattern(TIME_FORMAT)));
        m.put(BP_BIZ_DATE, bizDate.toString(DATE_FORMATTER));
        m.put(BP_MSG_ID, StringPool.EMPTY);
        m.put(BP_SVR_CODE, StringPool.EMPTY);
        m.put(BP_PARTNER_ID, PARTNERID);
        m.put(BP_CHANNEL_NO, M);
        m.put(BP_PUBLIC_KEY_CODE, PUBLIC_KEY_CODE);
        m.put(BP_FIELD_1, StringPool.EMPTY);
        m.put(BP_FIELD_2, StringPool.EMPTY);
        m.put(BP_FIELD_3, StringPool.EMPTY);
        m.put(BP_VERSION, VERSION);
        m.put(BP_CHARSET, StringPool.UTF_8);

        m.put("service", "getOrderInfo");

        m.put("outerOrderNo", orderNo);
        unSigncontent = sortParams(m);
        final Interfacecallrecord interfacecallrecord = Interfacecallrecord.createRecord("getOrderInfo", PARTNERID, bizDate, unSigncontent);

        String signcontent;
        try {
            signcontent = CertUtil.keyPairSign4Merchant(unSigncontent);
            String s = sendHttpMsg(signcontent);
            if (!Strings.isNullOrEmpty(s)) {
                interfacecallrecord.setResponse(s);
                Logger.info("the bank Interface [getOrderInfo] response is {}", s);
                return Optional.of(OrderInfoRspDto.create(s));
            } else {
                interfacecallrecord.setFail("银行接口访问错误");
                Logger.error("Bank Interface [ getOrderInfo ] return empty message! ");
                return Optional.absent();
            }
        } catch (Exception e) {
            interfacecallrecord.setFail("银行接口访问错误");
            Logger.error("Bank Interface [ getOrderInfo ] has error!", e);
        } finally {
            interfacecallrecord.save();
        }
        return Optional.absent();

    }

    public Optional<AccountAmountRspDto> getMerchantAccntAmount(DateTime createDatetime, DateTime bizDate) {
        String unSigncontent;
        Map<String, String> m = Maps.newHashMap();

        m.put("amount", "");
        m.put(BP_CREATE_DATE, createDatetime.toString(DATE_FORMATTER));
        m.put(BP_CREATE_TIME, createDatetime.toString(DateTimeFormat.forPattern(TIME_FORMAT)));
        m.put(BP_BIZ_DATE, bizDate.toString(DATE_FORMATTER));
        m.put("currency", "CNY");
        m.put("desc", "");
        m.put(BP_FIELD_1, StringPool.EMPTY);
        m.put(BP_FIELD_2, StringPool.EMPTY);
        m.put(BP_FIELD_3, StringPool.EMPTY);
        m.put(BP_MSG_ID, StringPool.EMPTY);
        m.put(BP_SVR_CODE, StringPool.EMPTY);
        m.put(BP_PARTNER_ID, PARTNERID);
        m.put(BP_CHANNEL_NO, M);
        m.put(BP_PUBLIC_KEY_CODE, "00");
        m.put(BP_VERSION, VERSION);
        m.put(BP_CHARSET, StringPool.UTF_8);
        m.put(BP_SERVICE, "getMerchantAccntAmount");

        unSigncontent = sortParams(m);
        Interfacecallrecord interfacecallrecord = Interfacecallrecord.createRecord("getMerchantAccntAmount", PARTNERID, bizDate,unSigncontent);

        String signcontent;
        try {
            signcontent = CertUtil.keyPairSign4Merchant(unSigncontent);
            String s = sendHttpMsg(signcontent);
            if (!Strings.isNullOrEmpty(s)) {
                interfacecallrecord.setResponse(s);
                return Optional.of(AccountAmountRspDto.create(s));
            }
            interfacecallrecord.setFail("银行返回内容为空");
        } catch (Exception e) {
            interfacecallrecord.setFail("银行接口访问错误");
            Logger.error("Bank Interface [ getMerchantAccntAmount ] has error!", e);
        } finally {
            interfacecallrecord.save();
        }

        return Optional.absent();
    }


    private static String sortParams(Map<String, String> params) {
        String result = StringPool.EMPTY;
        String[] args = new String[params.size()];
        Set<String> keys = params.keySet();
        Iterator<String> iterator = keys.iterator();
        int i = 0;
        while (iterator.hasNext()) {
            args[i] = iterator.next();
            i++;
        }
        Arrays.sort(args);

        String value;
        for (String key : args) {
            value = params.get(key);
            result = result + "&" + key + "=" + value;
        }
        if (result.length() > 0) {
            result = result.substring(1);
        }
        return result;
    }

    private String sendHttpMsg(String content) {

        HttpURLConnection conn;
        OutputStream out = null;
        PrintWriter pw = null;
        try {
            URL u = new URL(BANK_URL);
            conn = (HttpURLConnection) u.openConnection();

            conn.setRequestMethod("POST");
            conn.setDoInput(true);
            conn.setDoOutput(true);

            conn.setRequestProperty("content-type", "text/html");
            conn.connect();
            try {
                out = conn.getOutputStream();
                pw = new PrintWriter(out);
                pw.print(content);
                pw.flush();
                out.flush();
            } finally {
                IOUtils.closeQuietly(pw);
                IOUtils.closeQuietly(out);
            }

            InputStream is = conn.getInputStream();

            return IOUtils.toString(is, StringPool.UTF_8);

        } catch (UnknownHostException e) {
            Logger.error("unknown host bank interface url!", e);
        } catch (MalformedURLException e) {
            Logger.error("unknown host bank interface url!", e);
        } catch (ProtocolException e) {
            Logger.error("unknown host bank interface url!", e);
        } catch (IOException e) {
            Logger.error("read bank interface url has error!", e);
        }

        return null;

    }


    /**
     * 私有构造函数,确保对象只能通过单例方法来调用.
     */
    private BankService() {
    }

}
